package com.dong.web;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.dong.web.annotation.ContentType;
import com.dong.web.annotation.Json;
import com.dong.web.annotation.WriterContent;
import com.dong.web.clazz.ClazzHandler;
import com.dong.web.clazz.bean.ABean;
import com.dong.web.initialized.InitializeInvoke;
import com.dong.web.tool.AForm;
import com.dong.web.tool.AMap;
import com.dong.web.tool.HashAMap;
import com.dong.web.tool.MultiForm;
import com.dong.web.tool.MultiForms;
import com.dong.web.util.ActionUtil;
import com.dong.web.util.ClassUtil;
import com.dong.web.util.StringUtil;
import com.dong.web.util.WebUtil;
import com.dong.web.whold.Variables;

public final class DongServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;

	public void execute(HttpServletRequest req, HttpServletResponse res) {
		try {
			String key = getKey(req);
			if (ClazzHandler.ACTION_BEAN.containsKey(key)) {
				String PACKAGE = Variables.PACKAGE;
				ABean bean = ClazzHandler.ACTION_BEAN.get(key);
				Object obj = bean.getObject();
				Method[] methods = bean.getMethods();
				String methodParam = req.getParameter("method");
				Map<String, Method> actionMethods = bean.getActionMethods();
				Method method = ClassUtil.getMethod(actionMethods, methods,
						methodParam == null ? "execute" : methodParam);
				Type[] types = method.getGenericParameterTypes();
				Object[] parameters = new Object[types.length];
				int index = 0;
				AMap<String, Object> attribute = null;
				for (Type type : types) {
					if (type.equals(AMap.class)
							|| type.toString().startsWith(PACKAGE + ".AMap")) {
						attribute = new HashAMap<String, Object>();
					}
					parameters[index] = type.equals(HttpServletRequest.class) ? req
							: type.equals(HttpServletResponse.class) ? res
									: type.equals(AForm.class)
											|| type.toString().startsWith(
													PACKAGE + ".AForm") ? ActionUtil
											.getMap(req)
											: type.equals(AMap.class)
													|| type.toString()
															.startsWith(
																	PACKAGE
																			+ ".AMap") ? attribute
													: type.equals(MultiForms.class)
															|| type.toString()
																	.startsWith(
																			PACKAGE
																					+ ".MultiForms") ? ActionUtil
															.getMultiForms(req)
															: type.equals(MultiForm.class)
																	|| type.toString()
																			.startsWith(
																					PACKAGE
																							+ ".MultiForm") ? ActionUtil
																	.getMultiForm(req)
																	: null;
					index++;
				}
				if (method.isAnnotationPresent(WriterContent.class)
						&& method.getAnnotation(WriterContent.class).value()) {
					Type returnType = method.getGenericReturnType();
					if (returnType.equals(void.class)) {
						method.invoke(obj, parameters);
					} else {
						Object returnValue = null;
						try {
							returnValue = method.invoke(obj, parameters);
						} catch (Exception e) {
							e.printStackTrace();
						}
						res.setCharacterEncoding(Variables.ENCODING);
						String contentType = "";
						if (method.isAnnotationPresent(ContentType.class)) {
							contentType = method.getAnnotation(
									ContentType.class).value();
						}
						if (contentType == null || contentType.length() == 0) {
							res.setContentType("text/html;charset="
									+ Variables.ENCODING);
						} else {
							contentType = contentType.trim();
							if (contentType.toLowerCase().indexOf("charset") == -1) {
								if (!contentType.endsWith(";")) {
									contentType += ";";
								}
								contentType += "charset=" + Variables.ENCODING;
							}
							res.setContentType(contentType);
						}
						PrintWriter writer = res.getWriter();
						writer.print(returnValue);
						writer.flush();
						writer.close();
					}
				} else {
					Type returnType = method.getGenericReturnType();
					if (returnType.equals(String.class)) {
						String returnValue = "";
						try {
							returnValue = method.invoke(obj, parameters)
									.toString();
						} catch (Exception e) {
							e.printStackTrace();
						}
						if (method.isAnnotationPresent(Json.class)
								&& method.getAnnotation(Json.class).value()) {
							res.setCharacterEncoding(Variables.ENCODING);
							res.setContentType("text/json;charset="
									+ Variables.ENCODING);
							PrintWriter writer = res.getWriter();
							writer.print(returnValue);
							writer.flush();
							writer.close();
						} else {
							if (attribute != null) {
								for (Map.Entry<String, Object> entry : attribute
										.entrySet()) {
									req.setAttribute(entry.getKey(),
											entry.getValue());
								}
							}
							req.getRequestDispatcher(returnValue).forward(req,
									res);
						}
					} else if (returnType.equals(Redirect.class)) {
						Redirect redirect = (Redirect) method.invoke(obj,
								parameters);
						String url = redirect.getUrl();
						res.sendRedirect(url);
					} else {
						try {
							method.invoke(obj, parameters);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
			} else {
				// req.getRequestDispatcher(key).forward(req, res);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void init() throws ServletException {
		String scanning = this.getServletConfig().getInitParameter("scanning");
		scanning = StringUtil.replaceBlank(scanning);
		Variables.SCANNING = scanning;
		ClazzHandler.find(scanning);
		String run = this.getServletConfig()
				.getInitParameter("initializeClass");
		if (run != null) {
			run = StringUtil.replaceBlank(run);
			String[] names = run.split(",");
			try {
				for (String name : names) {
					Class<?> clazz = Class.forName(name);
					InitializeInvoke init = (InitializeInvoke) clazz
							.newInstance();
					init.run();
				}
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			}
		}
		String upload = this.getServletConfig().getInitParameter("upload");
		File file = null;
		if (upload != null) {
			upload = StringUtil.replaceRn(upload);
			Variables.UPLOAD_ROOT = upload;
			String[] valued = upload.split(",");
			for (String value : valued) {
				value = value.trim();
				String url = ClassUtil.getProjectPath() + value;
				file = new File(url);
				if (!file.exists()) {
					file.mkdirs();
				}
			}
		}
	}

	private String getKey(HttpServletRequest req) {
		String root = WebUtil.getRoot(req);
		String uri = req.getRequestURI();
		if (uri.startsWith(root)) {
			uri = uri.substring(root.length());
		}
		return uri;
	}

	public void doGet(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		doPost(req, res);
	}

	public void doPost(HttpServletRequest req, HttpServletResponse res)
			throws ServletException, IOException {
		execute(req, res);
	}

}
